/**
 * FormModelUtil.java
 *
 * Copyright (c) 2009 viorelt All Rights Reserved.
 *
 * This source file may not be copied, modified or redistributed,
 * in whole or in part, in any form or for any reason, without the express
 * written consent of viorelt .
 **/
package ro.prjmanager.core.util;


import net.sourceforge.stripes.action.FileBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.web.context.support.WebApplicationContextUtils;
import ro.prjmanager.core.annotations.Column;
import ro.prjmanager.core.annotations.EditOptions;
import ro.prjmanager.core.annotations.Id;
import ro.prjmanager.core.annotations.SelectOption;
import ro.prjmanager.core.context.SecurityContext;
import ro.prjmanager.core.service.Service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.Field;

public class FormModelUtil<F, M> {
    public static final Log log = LogFactoryImpl.getLog(FormModelUtil.class);
    F form;
    M model;
    SecurityContext context;


    public FormModelUtil(F form, M model) {
        this.form = form;
        this.model = model;
    }

    public FormModelUtil(F form, M model, SecurityContext context) {
        this.form = form;
        this.model = model;
        this.context = context;
    }

    public F getForm() {
        log.debug("*******************************************Resurceting form:");
        if (model == null)
            return form;
        BeanWrapperImpl bean = new BeanWrapperImpl(model);
        Field[] fields = form.getClass().getDeclaredFields();
        for (Field field : fields) {
            Id id = field.getAnnotation(Id.class);
            if (id != null) {
                Object idVal;
                bean.setWrappedInstance(model);
                idVal = bean.getPropertyValue(id.name());
                bean.setWrappedInstance(form);
                bean.setPropertyValue(field.getName(), idVal);
            }

            Column col = field.getAnnotation(Column.class);
            if (col == null)
                continue;
            bean.setWrappedInstance(model);


            String attModelName = col.index();
            Object beanModel = bean.getPropertyValue(attModelName);
            if (beanModel != null) {
                SelectOption selOpt = field.getAnnotation(SelectOption.class);
                if (selOpt != null) {
                    bean.setWrappedInstance(beanModel);
                    Integer ids = (Integer) bean.getPropertyValue(selOpt.idOption());
                    bean.setWrappedInstance(form);
                    bean.setPropertyValue(field.getName(), ids);
                } else {
                    bean.setWrappedInstance(form);
                    bean.setPropertyValue(field.getName(), beanModel);


                }
            }
        }

        return form;

    }

    public M getModel() {
        if (form == null)
            return model;
        BeanWrapperImpl bean = new BeanWrapperImpl(form);
        Field[] fields = form.getClass().getDeclaredFields();
        for (Field field : fields) {
            Id id = field.getAnnotation(Id.class);
            if (id != null) {
                Object idVal;
                bean.setWrappedInstance(form);
                idVal = bean.getPropertyValue(field.getName());
                bean.setWrappedInstance(model);
                bean.setPropertyValue(id.name(), idVal);
            }
            Column col = field.getAnnotation(Column.class);
            if (col == null)
                continue;
            bean.setWrappedInstance(form);
            Object beanForm = bean.getPropertyValue(field.getName());
            if (col.editOptions().edittype().equals("checkbox")) {
                beanForm = beanForm != null && String.valueOf(beanForm).equals("off") ? Integer.valueOf("0") :
                        (beanForm != null && String.valueOf(beanForm).equals("on") ? Integer.valueOf("1") :
                                (beanForm != null && String.valueOf(beanForm).equals("false") ? Integer.valueOf("0") :
                                        beanForm != null && String.valueOf(beanForm).equals("true") ? Integer.valueOf("1") :
                                                beanForm
                                )
                        );
            }
            if (beanForm != null || field.getType().equals(FileBean.class)) {
                SelectOption selOpt = field.getAnnotation(SelectOption.class);
                if (selOpt != null) {
                    Integer ids = (Integer) beanForm;
                    String serviceName = selOpt.serviceName();
                    Service<M, Integer> service = getService(serviceName);
                    M bean1 = service.load(ids);
                    if (bean1 != null) {
                        String attName = col.index();
                        bean.setWrappedInstance(model);
                        bean.setPropertyValue(attName, bean1);
                    }

                } else {

                    EditOptions editOptions = col.editOptions();
                    if (editOptions != null && editOptions.edittype().equals("file")) {
                        bean.setWrappedInstance(model);
                        String attName = field.getName();
                        Object attVal = context.getRequest().getSession().getAttribute(attName);
                        if (attVal != null) {
                            ByteArrayInputStream is = (ByteArrayInputStream) attVal;

                            try {
                                byte[] file = new byte[is.available()];
                                is.read(file);
                                bean.setPropertyValue(field.getName(), file);
                            } catch (IOException e) {
                                log.error(e);
                            }
                        }
                    } else {
                        bean.setWrappedInstance(model);
                        Class clazz = bean.getPropertyType(field.getName());

                        Object newObj = null;
                        try {
                            newObj = ConvertUtil.cast(beanForm, clazz);
                        } catch (Exception e) {
                            log.error(e);
                        }
                        bean.setPropertyValue(field.getName(), newObj);
                    }
                }
            }
        }

        return model;


    }

    @SuppressWarnings("unchecked")
    private Service<M, Integer> getService(String serviceName) {
        return (Service<M, Integer>) WebApplicationContextUtils.getRequiredWebApplicationContext(context.getServletContext()).getBean(serviceName);
    }


}
